package pers.qianyu.auth.security.filter;

import cn.hutool.core.util.*;
import io.jsonwebtoken.*;
import org.springframework.security.authentication.*;
import org.springframework.security.core.*;
import org.springframework.security.core.context.*;
import org.springframework.security.web.authentication.www.*;
import pers.qianyu.auth.constants.*;
import pers.qianyu.auth.security.model.*;
import pers.qianyu.auth.utils.*;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.util.stream.*;

public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 获取令牌并根据令牌获取登录认证信息
        Authentication authentication = getAuthenticationFromToken(request);
        // 设置登录认证信息到上下文
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }

    /**
     * 根据请求令牌获取登录认证信息
     *
     * @param req 请求对象
     * @return 用户名
     */
    public static Authentication getAuthenticationFromToken(HttpServletRequest req) {
        Authentication authentication = null;
        // 获取请求携带的令牌
        String token = getToken(req);
        if (Objects.nonNull(token) &&
                Objects.nonNull(SecurityContextHolder.getContext()) &&
                Objects.nonNull(SecurityContextHolder.getContext().getAuthentication())) {
            if (JwtTokenUtils.isTokenExpired(token)) {
                return null;
            }
            Claims claims = JwtTokenUtils.getClaimsFromToken(token);
            if (Objects.isNull(claims)) {
                return null;
            }
            String username = claims.getSubject();
            if (Objects.isNull(username)) {
                return null;
            }
            List<GrantedAuthorityImpl> authorities = Optional.ofNullable(
                    (List<?>) claims.get(JwtConstants.AUTHORITIES))
                    .map(List::stream)
                    .orElseGet(Stream::empty)
                    .map(auth -> new GrantedAuthorityImpl((String) auth))
                    .collect(Collectors.toList());
            authentication = new JwtAuthenticationToken(username, null, authorities, token);
        }
        return authentication;
    }

    /**
     * 从请求中获取请求token
     *
     * @param req 请求对象
     * @return 存在就返回 token，否则返回 null
     */
    public static String getToken(HttpServletRequest req) {
        String token = req.getHeader(JwtConstants.HTTP_HEADER);
        if (Objects.isNull(token)) {
            return null;
        }
        if (token.contains(JwtConstants.TOKEN_PREFIX)) {
            token = StrUtil.subAfter(token, JwtConstants.TOKEN_PREFIX, false);
        }
        if (StrUtil.isBlank(token)) {
            return null;
        }
        return token;
    }
}